/***********************************************************************
 *
 * MODULE NAME:    le_cts_app.c
 * PROJECT CODE:   CEVA Low Energy Single Mode
 * DESCRIPTION:    Implementation of the Services required for Simple Server App and HID App.
 * MAINTAINER:     Gary Fleming
 * CREATION DATE:  June 2012
 *
 *
 * LICENSE:
 *     This source code is copyright (c) 2011-2012 Ceva Inc.
 *     All rights reserved.
 *
 ***********************************************************************/
#include "sys_types.h"
#include "sys_features.h"
#include "hc_const.h"
#include "hw_lc.h"
#include "hw_le_lc.h"
#include <stdio.h>
#include "include.h"
#include "le_connection.h"
#include "le_att.h"
#include "le_gatt_server.h"
#include "le_gap.h"
#include "le_gap_const.h"
#include "le_const.h"
#include "hc_const.h"
#include "hc_event_gen.h"
#include "tra_queue.h"
#include "bt_timer.h"
#include "sys_mmi.h"
#include "hw_le_lc_impl.h"
#include "LE_link_layer.h"
#include "le_smp.h"
#include "le_gap.h"
#include "le_l2cap.h"
#include "le_cts_app.h"
#include "lmp_utils.h"
#include "gatt_service_hid.h"
#include "gatt_service_ancs.h"
#include "le_config.h"
#include "sys_power.h"
#include "DeviceBtj_Header.h"
#include "updata_gatt_service.h"

//gap params
u_int8 gap_name_array[] = "BK3431S";
#if(GATT_SERVICE_HID_GAMEPAD)
u_int8 gap_appearance_array[2] = {0x03,0xC3} ; // joy stick
#else
u_int8 gap_appearance_array[2] = {0x03,0xC1} ; // Hid Keyboard
#endif
u_int8 gap_connection_params[8] = {0x18,0x00,0xff,0x00,0x0a,0x00,0xd0,0x07};
u_int8 GATTprivacy_Flags=0;
//gatt params
u_int8 Service_Change_Range[4] = {0x01,0x00,0x4F,0x01};
u_int8 GATT_service_change_CCC[2] = {0x00,0x00};
//device infomation params
u_int8 manufacturer_name_string[10] = "BEKEN";
u_int8 model_number_string[7] = "BT 4.0";
u_int8 serial_number_string[11] = "12x07x2016";
u_int8 fw_revision_string[5] = "01.1";
u_int8 sw_revision_string[5] = "01.1";
u_int8 hw_revision_string[5] = "SM-1";
u_int8 system_id[8] = {0,0,0,0,0,0,0,0};//{0xDE,0xBC,0x9A,0xFE,0xFF,0x56,0x34,0x12};
u_int8 pnp_id[7] = {0x01,0x0E,0x00,0x12,0x34,0x01,0x67};
u_int8 IEEE_Reg_Cert[14] = {0xFE,0x00,0x65,0x78,0x70,0x65,0x72,0x69,0x6D,0x65
                            ,0x6E,0x74,0x61,0x6C
                           };//{0x89,0xAB,0xCD,0xEF};
u_int16 g_handle=1;
t_App_Control LEapp_Config;
u_int16 LE_App_ACL_Handle = 0;
u_int8 App_Config_App_Present = 1;
u_int8 link_vars_buff[LINK_BUF_LEN];
u_int16 direct_advertising_time;

#if(GATT_SERVICE_HID)
const u_int8  gatt_service_adv_data[20]=
{
    0x02, 0x01, 0x06,
    0x03, 0x03, 0x12, 0x18,
#if(GATT_SERVICE_HID_GAMEPAD)
    0x03, 0x19, 0xC3, 0x03,
#else
    0x03, 0x19, 0xC1, 0x03,
#endif
    0X08, 0X09, 'B','K','3','4','3','1','S'
};
#endif
#if(GATT_SERVICE_FIND_ME)
const u_int8  gatt_service_adv_data[]=
{
    0x02,0x01,0x06
    0x02,0x0A,0x00,
    0x07,0x02,0x03,0x18,0x02,0x18,0x04,0x18
};
#endif
#if(GATT_SERVICE_USER_DEFINE)
const u_int8 gatt_service_adv_data[] =
{
    0x02,0x01,0x06,
    0x03, 0x02, 0xE0, 0xFF,
    0X08, 0X09, 'B','K','3','4','3','1','S'
};
#endif
const u_int8  gatt_service_scan_resp_data[9] =
{
    0x08,   // length of this data
    0x09,   // AD Type = Complete local name
    'B','K','3','4','3','1','S'
};
void LE_APP_GATT_Event_Handler(u_int8 eventCode, t_gatt_event_params* p_gatt_event_params);
void LE_APP_GATT_Command_Complete(u_int8 operation_id,t_gatt_command_complete_params* p_params);
void LE_APP_GAP_Connection_Complete(u_int8 eventCode, t_gap_event_params* p_gap_event_params);
void ReadLinkVars(void)
{
    u_int8 temp_buf[32];
    u_int8 i=0;
    // flash_set_line_mode(1);
    flash_read_data(temp_buf,0x41000,LINK_BUF_LEN);
    for(i=0; i<LINK_BUF_LEN; i++)
    {
        link_vars_buff[i]= temp_buf[i];
    }
    //flash_set_line_mode(4);  //??
}
void WriteLinkVars(void)
{
    u_int8 temp_buf[32];
    u_int8 i=0;
    flash_set_line_mode(1);
    flash_erase_sector(0x41000);
    for(i=0; i<LINK_BUF_LEN; i++)
    {
        temp_buf[i] = link_vars_buff[i];
    }
    flash_write_data(temp_buf,0x41000,LINK_BUF_LEN);
    flash_set_line_mode(4);
}
void ClearLinkVars(void)
{
    u_int8 temp_buf[32];
    flash_set_line_mode(1);
    flash_read_data(temp_buf,0x41000,32); //delay
    flash_erase_sector(0x41000);
    flash_set_line_mode(4);
}
void LE_APP_Init(void)
{
    // Initially for fully embedded Proximity, IAS and Find Me
    u_int32 current_clk = HW_Get_Native_Clk_Avoid_Race();
#if(WHITELIST_ONEDEVICE_EN)
    LINK_VARS *p_link_vars;
    p_link_vars = (pLINK_VARS)link_vars_buff;
#endif
    App_Config_App_Present = 1;
    LEapp_Config.Alert_Level = 0x00;
    LEapp_Config.empty_packet_flag=0;
    LEapp_Config.empty_packet_cnt=0xffff;
    LEapp_Config.TAPP_L2CAP_PARA_UPDATE_Timer = BT_TIMER_OFF;
    LEapp_Config.SMP_security_request_timer = BT_TIMER_OFF;
    LEapp_Config.TAPP_POWERON_STANDBY_Timer = BT_TIMER_OFF;
    LEapp_Config.ancs_config_start_timer = BT_TIMER_OFF;
    LEapp_Config.TAPP_Advertising_Timer = current_clk+ADVERTISING_TIMER;
#if(PRH_BS_CFG_SYS_LE_GATT_INCLUDED==1)
    // Register Callbacks for GATT Event and GATT Command Complete handling
    GATT_Register_Callbacks((void*)LE_APP_GATT_Event_Handler,(void*)LE_APP_GATT_Command_Complete);
#endif
    GAP_Register_Callbacks((void*)LE_APP_GAP_Connection_Complete, (void*)0x00);
#if(GATT_SERVICE_HID)
    LEsmp_Configure_Security(
                                SMP_NoInputNoOutput /* io_capability - SMP_NoInputNoOutput  */,
                                0x00 /* oob_flag - Data Not Present */,
                                SMP_AUTHREQ_BONDING_NO_MITM /* auth_req - Bonding / !MITM */,
                                0x10 /* max_encry_key_size*/,
                                0x07 /* min_encry_key_size */,
                                0x07 /* initiator_key_dist - ID Key Enc Key */,
                                0x07 /* responder_key_dist - ID Key Enc Key */
                                ,0
                            );
#endif
#if(GATT_SERVICE_FIND_ME)
    LEsmp_Configure_Security(
                                SMP_NoInputNoOutput /* io_capability - SMP_NoInputNoOutput  */,
                                0x00 /* oob_flag - Data Not Present */,
                                SMP_AUTHREQ_NO_BONDING_NO_MITM /* auth_req - Bonding / !MITM */,
                                0x10 /* max_encry_key_size*/,
                                0x07 /* min_encry_key_size */,
                                0x01 /* initiator_key_dist - ID Key Enc Key */,
                                0x01 /* responder_key_dist - ID Key Enc Key */
                                ,0
                            );
#endif
#if(GATT_SERVICE_USER_DEFINE)
    LEsmp_Configure_Security(
                                SMP_DisplayOnly,
                                0x00,
                                SMP_AUTHREQ_BONDING_MITM,
                                0x10,
                                0x07,
                                0x03,
                                0x03,
                                123456
                                );
#endif
    GAP_Set_AD_Data(sizeof(gatt_service_adv_data),(u_int8*)gatt_service_adv_data);
    GAP_Set_ScanResp_Data(sizeof(gatt_service_scan_resp_data),(u_int8*)gatt_service_scan_resp_data);//C_Chip
    direct_advertising_time=DIRECT_ADVERTISING_TIME;
#if(WHITELIST_ONEDEVICE_EN)  //modify frank
    ReadLinkVars();
    if(((p_link_vars->init_addr_type) == 0xff) && ((p_link_vars->own_addr_type) == 0xff))
    {
        GAP_Discoverable_Mode(GAP_GENERAL_DISCOVERABLE,ADV_IND,ADVERTISING_INTERVAL,direct_advertising_address);
    }
    else
    {
        LEwl_Clear_White_List();
        LEwl_Add_Device_To_White_List(p_link_vars->init_addr_type, p_link_vars->init_addr);
        GAP_Discoverable_Mode(GAP_GENERAL_DISCOVERABLE,ADV_IND,ADVERTISING_INTERVAL,direct_advertising_address);
        LEadv_Set_Advertising_Filter_Policy(0x01); //open frank 2016 0513
    }
#else
    GAP_Discoverable_Mode(GAP_GENERAL_DISCOVERABLE,ADV_IND,ADVERTISING_INTERVAL,direct_advertising_address);

#endif
}
/**************************************************************************
 * FUNCTION :- LE_App_Local_Event_Indication
 *
 * DESCRIPTION
 * This function is triggered on receipt of a Write_Indication Event/Callback from
 * the GATT layer.
 *
 * For each handle the local GATT DB is read to determine the new value which has
 * been written into the DB by the Peer. An Application Event is then generated to
 * inform the App/User of the new value.
 *
 * INPUTS
 * u_int16 attrib_handle - Handle which has been written to.
 * u_int8  status  :- Currently UNUSED
 *************************************************************************/
u_int8 LE_App_Local_Event_Indication(u_int16 attrib_handle, u_int8 status)
{
#if(PRH_BS_CFG_SYS_LE_GATT_INCLUDED==1)
    u_int8* p_value_array;
    u_int8 length;
    switch (attrib_handle)
    {
    case IAS_SERVER_IMMEDIATE_ALERT_HANDLE :
        GATTserver_Characteristic_Read_Local_Value(attrib_handle,&length,&p_value_array);
        break;
    default :
        break;
    }
#endif
    return NO_ERROR;
}
/**************************************************************************
 * FUNCTION :- LE_APP_GATT_Event_Handler
 *
 * DESCRIPTION
 * This key function is used to handle all events raised by the GATT layer.
 *
 *
 *
 * GATT_VALUE_NOTIFICATION_EVENT :
 * This occurs when one of the Current Time Characteristics has been modified by
 * the peer and we have previously enable notifications by writing to it's CCC.
 * In this cases we construct an APP_INDICATION event using the information in the
 * notification and sent it to the application.
 *
 * GATT_READ_RESPONSE_EVENT
 * If a READ_RESPONSE_EVENT is recieved for a handle which is valid (i.e not zero).
 * The the payload in the READ_RESPONSE will be sent to the application in an
 * APP_INDICATION event.
 *
 * The READ_RESPONSE_EVENT is also used to trigger discovery of the peers CTS and NDST
 * handles.
 *
 * GATT_DISCOVER_SERVICES_BY_UUID_EVENT
 * This the response to the Discover Services by UUID request which was issued to determine the Handles
 * ranges in use of the CTS and NDST profiles.
 *
 * GATT_DISCOVER_CHARACTERISTICS_EVENT
 * This the response to the Discover Characteristics request which was issue to determine the values of
 * the handles for the Characterisitics of the CTS and NDST profiles.
 *
 * INPUTS
 * u_int8 eventCode              - Identifier for the Event
 * u_int8* p_gatt_event_params   - pointer to a structure of GATT event Parameters
 *
 *************************************************************************/
void LE_APP_GATT_Event_Handler(u_int8 eventCode, t_gatt_event_params* p_gatt_event_params)
{
    switch(eventCode)
    {
    case GATT_READ_RESPONSE_EVENT :
        
    break;
    case GATT_VALUE_NOTIFICATION_EVENT :
    {
        if (p_gatt_event_params->status==0x00) 
            get_ancs_notification(p_gatt_event_params->payload);
              
    }
    break;
    case GATT_DISCOVER_SERVICES_BY_UUID_EVENT :
    {
#if(GATT_SERVICE_ANCS)    
        //IOS ANCS SERVICE
        sys_flag |= FLAG_IOS_SERVICE;
#endif
    }
    break;
    case GATT_DISCOVER_CHARACTERISTICS_EVENT :
    {
        get_ancs_characteristic(p_gatt_event_params);
    }
    break;
    case GATT_WRITE_INDICATION_EVENT :
        LE_App_Local_Event_Indication(p_gatt_event_params->att_handle,p_gatt_event_params->status);
    break;
    }
}
void LE_L2CAP_Response_Event_Handler(u_int8 eventCode, u_int8 status)
{
    extern t_LE_Config LE_config;
    t_LE_Connection* p_connection  = LEconnection_Find_Link_Entry(LE_config.active_link);
    
    if(eventCode==L2CAP_CONNECTION_PARAMETER_UPDATE_RESPONSE)
    {
        if(status==0)
        {
            ;
        }
    }
    else if(eventCode==L2CAP_CONNECTION_PARAMETER_UPDATE_REQUEST)
    {

        //p_connection->connInterval_new;
        //p_connection->latency_new;
        //p_connection->timeout_new;
        ;
    }

}

void _GAP_Init_GAP_Discovery(t_LE_Connection* p_connection)
{
    extern t_GAP_config     LEgap_Config;
    //if (LEgap_Config.Connect_Mode != GAP_NO_CONNECT)
    {
        //u_int8 gap_UUID[2] = {0x00,0x18};
#if(GATT_SERVICE_ANCS)
        u_int8 gap_UUID[16] = {0XD0,0X00,0X2D,0X12,0X1E,0X4B,0X0F,0XA4,
                               0X99,0X4E,0XCE,0XB5,0X31,0XF4,0X05,0X79
                              };
#else
        u_int8 gap_UUID[2] = {0x00,0x18};
#endif
        u_int16 handle = LEconnection_Determine_Connection_Handle(p_connection);
        // First need to get the Handle Range for GAP on the peer device.
        // Then need to determine the Handles for the Privacy Flag and Re-Connection
        // address
        LEgap_Config.state = GAP_W4_PEER_GAP_HANDLE_RANGE;

#if(GATT_SERVICE_ANCS)
        GATT_Discover_Primary_Service(handle,0x01,gap_UUID,GAP_PROTOCOL);
#else
        GATT_Discover_Primary_Service(handle,0x00,gap_UUID,GAP_PROTOCOL);
#endif
    }
}
/**************************************************************************
 * FUNCTION :- LE_App_Local_Disconnect_Indication
 *
 * DESCRIPTION
 * This the Callback function invoked by the Lower layers layer when a connection is disconnected
 * either by the peer or due to link loss.
 *
 * Since the 'Simple Server Application' encompasses the link loss profile, the
 * Link Loss IAS alert characteristic will be read from the local GATT DB and an alerting
 * event will be send to the application.
 *
 * For all applications a Disconnect Event will be sent to the application and the GAP
 * will be instructed to place the device in CONNECTABLE mode. A 'Connectable' event will
 * also be sent to the application.
 *************************************************************************/
u_int8 LE_App_Local_Disconnect_Indication(t_error reason)
{
    DEBUG_MSG(0X05);
    GAP_Discoverable_Mode(GAP_GENERAL_DISCOVERABLE,ADV_IND,ADVERTISING_INTERVAL,direct_advertising_address);
    LEapp_Config.TAPP_L2CAP_PARA_UPDATE_Timer = BT_TIMER_OFF;
    LEapp_Config.empty_packet_flag=0;
    LEapp_Config.empty_packet_cnt=0xffff;
    sys_flag &= ~FLAG_CONNECTED;
    sys_flag &= ~FLAG_IOS_SERVICE;
    tx_buff_head=0;
    tx_buff_tail=0;  
    tx_buff_count=0;
    suspend_low_power_mode=0;
    updata_start=0;
    return NO_ERROR;
}
/**************************************************************************
 * FUNCTION :- LE_APP_GAP_Connection_Complete
 *
 * DESCRIPTION
 * This the Callback function invoked by the GAP layer when a connection complete has been
 * recieved from the lower layers and any necessary processing (i.e setup of an encrypted link)
 * is complete.
 *
 * This is mainly used by the CTS based app (Server Simple Service) to cancle alerting
 * (if the Proximity/Link Loss was in use). Also used to trigger Discovery for the handles
 * of the Timer Characteristics on the Peer device.
 *************************************************************************/
void LE_APP_GAP_Connection_Complete(u_int8 event,t_gap_event_params* p_event_params )
{
    extern t_LE_Config LE_config;
    extern u_int8 tx_buff_count;
    u_int32 current_clk = HW_Get_Native_Clk_Avoid_Race();
    t_LE_Connection* p_connection  = LEconnection_Find_Link_Entry(LE_config.active_link);
    p_connection->encry_key_size=16;

#if(WHITELIST_ONEDEVICE_EN)
    u_int8 i=0;
    LINK_VARS *p_link_vars;
    p_link_vars = (pLINK_VARS)link_vars_buff;
#endif
    
    if (p_event_params->status == NO_ERROR)
    {
        LE_App_ACL_Handle = p_event_params->handle;
        if(App_Config_App_Present && (p_event_params->status == NO_ERROR))
        {
            if( (current_clk+L2CAP_PARA_UPDATE_TIME)>BT_CLOCK_MAX_TICKS )
            {
                LEapp_Config.TAPP_L2CAP_PARA_UPDATE_Timer=(current_clk+L2CAP_PARA_UPDATE_TIME)-BT_CLOCK_MAX_TICKS;
            }
            else
            {
                LEapp_Config.TAPP_L2CAP_PARA_UPDATE_Timer = current_clk+L2CAP_PARA_UPDATE_TIME;
            }
            if( (current_clk+SMP_SECURITY_REQUEST_TIME)>BT_CLOCK_MAX_TICKS )
            {
                LEapp_Config.SMP_security_request_timer=(current_clk+SMP_SECURITY_REQUEST_TIME)-BT_CLOCK_MAX_TICKS;
            }
            else
            {
            LEapp_Config.SMP_security_request_timer= current_clk+SMP_SECURITY_REQUEST_TIME;
            }
            LEapp_Config.TAPP_POWERON_STANDBY_Timer = BT_CLOCK_MAX_TIMEOUT;

#if(GATT_SERVICE_ANCS)
            _GAP_Init_GAP_Discovery(p_connection);
#endif
#if(WHITELIST_ONEDEVICE_EN)
            // ReadLinkVars();
            if(((p_link_vars->init_addr_type) == 0xff) && ((p_link_vars->own_addr_type) == 0xff))
            {
                for(i=0; i<6; i++)
                {
                    p_link_vars->init_addr[i] = p_connection->peer_address.bytes[i];
                }
                p_link_vars->init_addr_type = p_connection->peer_address_type;
                p_link_vars->own_addr_type = p_connection->own_address_type;
                WriteLinkVars();
                LEwl_Clear_White_List();
                LEwl_Add_Device_To_White_List(p_link_vars->init_addr_type, p_link_vars->init_addr); //init_a
                LEadv_Set_Advertising_Filter_Policy(0x01);
            }
#endif
        }
    }
    else
    {
        GAP_Discoverable_Mode(GAP_GENERAL_DISCOVERABLE,ADV_IND,ADVERTISING_INTERVAL,direct_advertising_address);
    }
    return;
}
/**************************************************************************
 * FUNCTION :- LE_APP_GATT_Command_Complete
 *
 * DESCRIPTION
 * This the Callback function invoked by the GATT layer when a procedure is complete
 * It is used by the Current Time Application to allow the Discovery of the Handles for
 * Time Characteristics on the Peer Devices GATT DB.
 *
 * It is used in combination with 'LE_APP_GATT_Event_Handler' to progress through the
 * discovery state machine. Once discovery is complete it also writes to the Client
 * Charactaristic Configuration for the Current Time Characteristic
 *************************************************************************/
#if(PRH_BS_CFG_SYS_LE_GATT_INCLUDED==1)
void LE_APP_GATT_Command_Complete(u_int8 operation_id,t_gatt_command_complete_params* p_params)
{
    switch(operation_id)
    {
    case 0x01 :// Primary Service Discovery :
        break;
    case 0x03 : // GATT_CHARACTERISTIC_DISCOVERY :
        break;
    }
}
#endif
/**************************************************************************
 * FUNCTION :- LE_App_Generate_Event
 *
 * DESCRIPTION
 * Simple function for encoding Events which have to be sent to the Application
 * over the Serial/UART IF.
 *
 *************************************************************************/
void LE_App_Generate_Event(u_int8 event,u_int8 para1,u_int8* p_data)
{
#if 0
    u_int8* p_buffer;
    u_int8  i;
    struct q_desc* qd;
    /*
     * Determine event length:
     *     2 bytes for event header
     *     1 byte for event
     *     1 byte for param
     */
    if (!App_Config_App_Present)
    {
        return;
    }
    if (event == APP_SCAN_INTERVAL_INDICATION)
    {
        qd=BTq_Enqueue(HCI_EVENT_Q, 0, (t_length)
                       (6+SIZE_OF_EVENT_HEADER ) );
    }
    else if (( event ==  APP_LOCAL_TIME_INFORMATION_UPDATE_INDICATION ) ||
             ( event == APP_CURRENT_TIME_UPDATE_INDICATION ) ||
             ( event == APP_REFERENCE_TIME_INFORMATION_UPDATE_INDICATION ) ||
             ( event == APP_DATE_TIME_WITH_DST_UPDATE_INDICATION) ||
             ( event == APP_HID_REPORT_OUTPUT_INDICATION) ||
             ( event == APP_HID_BOOT_KEYBOARD_OUTPUT_INDICATION)||
             ( event ==APP_HID_BOOT_KEYBOARD_INPUT_INDICATION)||
             ( event ==APP_HID_BOOT_MOUSE_INPUT_INDICATION)||
             ( event ==APP_HID_REPORT_FEATURE_INDICATION)||
             ( event ==APP_HID_REPORT_INPUT_INDICATION) ||
             ( event ==APP_HID_CONTROL_POINT_INDICATION) ||
             ( event ==APP_HRS_CONTROL_POINT_INDICATION) ||
             ( event ==APP_CSC_REPORT_CONTROL_POINT_INDICATION) ||
             ( event ==APP_RSC_REPORT_CONTROL_POINT_INDICATION) ||
             ( event ==APP_HID_PROTOCOL_MODE_INDICATION) ||
             ( event ==APP_HT_MEASUREMENT_INTERVAL_INDICATION)
            )
    {
        qd=BTq_Enqueue(HCI_EVENT_Q, 0, (t_length)
                       (para1+2+SIZE_OF_EVENT_HEADER ) );
    }
    else
    {
        qd=BTq_Enqueue(HCI_EVENT_Q, 0, (t_length)
                       (2+SIZE_OF_EVENT_HEADER ) );
    }
    if(qd)
    {
        p_buffer = qd->data;
    }
    else
    {
        return;
    }
    switch(event)
    {
    case APP_ALERTING_EVENT :
    case APP_CONNECT_EVENT :
    case APP_DISCONNECT_EVENT :
    case APP_CONNECTABLE_EVENT :
        p_buffer[2] = event;
        p_buffer[3] = para1;
        break;
    case APP_SCAN_INTERVAL_INDICATION :
        p_buffer[2] = event;
        p_buffer[3] = para1;
        for (i=0; i<para1; i++)
        {
            p_buffer[4+i] = p_data[i];
        };
        break;
    case APP_HID_CONTROL_POINT_INDICATION :
    case APP_HID_PROTOCOL_MODE_INDICATION :
    case APP_HID_REPORT_INPUT_INDICATION :
    case APP_HID_REPORT_FEATURE_INDICATION :
    case APP_HID_BOOT_MOUSE_INPUT_INDICATION :
    case APP_HID_BOOT_KEYBOARD_INPUT_INDICATION :
    case APP_HID_BOOT_KEYBOARD_OUTPUT_INDICATION :
    case APP_HID_REPORT_OUTPUT_INDICATION :
    case APP_LOCAL_TIME_INFORMATION_UPDATE_INDICATION :
    case APP_CURRENT_TIME_UPDATE_INDICATION :
    case APP_REFERENCE_TIME_INFORMATION_UPDATE_INDICATION :
    case APP_DATE_TIME_WITH_DST_UPDATE_INDICATION :
    case APP_HRS_CONTROL_POINT_INDICATION :
    case APP_CSC_REPORT_CONTROL_POINT_INDICATION :
    case APP_RSC_REPORT_CONTROL_POINT_INDICATION :
    case APP_HT_MEASUREMENT_INTERVAL_INDICATION :
        p_buffer[2] = event;
        p_buffer[3] = para1;
        for (i=0; i<para1; i++)
        {
            p_buffer[4+i] = p_data[i];
        }
        break;
    }
    p_buffer[0] = HCI_LE_APP_EVENT;
    if (event == APP_SCAN_INTERVAL_INDICATION)
    {
        p_buffer[1] = 6;
    }
    else if (( event ==  APP_LOCAL_TIME_INFORMATION_UPDATE_INDICATION ) ||
             ( event == APP_CURRENT_TIME_UPDATE_INDICATION ) ||
             ( event == APP_REFERENCE_TIME_INFORMATION_UPDATE_INDICATION ) ||
             ( event == APP_DATE_TIME_WITH_DST_UPDATE_INDICATION) ||
             ( event == APP_HID_BOOT_KEYBOARD_OUTPUT_INDICATION) ||
             ( event == APP_HID_REPORT_OUTPUT_INDICATION) ||
             ( event == APP_HID_REPORT_INPUT_INDICATION ) ||
             ( event == APP_HID_REPORT_FEATURE_INDICATION ) ||
             ( event == APP_HID_BOOT_MOUSE_INPUT_INDICATION ) ||
             ( event == APP_HID_BOOT_KEYBOARD_INPUT_INDICATION ) ||
             ( event == APP_HID_CONTROL_POINT_INDICATION) ||
             ( event == APP_HRS_CONTROL_POINT_INDICATION) ||
             ( event == APP_CSC_REPORT_CONTROL_POINT_INDICATION ) ||
             ( event == APP_RSC_REPORT_CONTROL_POINT_INDICATION ) ||
             ( event == APP_HID_PROTOCOL_MODE_INDICATION) ||
             ( event == APP_HT_MEASUREMENT_INTERVAL_INDICATION)
            )
    {
        p_buffer[1] = para1+2;
    }
    else
    {
        p_buffer[1] = 2;
    }
    BTq_Commit(HCI_EVENT_Q, 0);
#endif
}
void LE_App_Connected_Detect(void)
{
    if(LEapp_Config.empty_packet_cnt<0xffff)
    {
        LEapp_Config.empty_packet_cnt++;
    }
}
void LE_App_Clear_Count(void)
{
    LEapp_Config.empty_packet_cnt=0;
}
void LE_APP_Connected()
{
    sys_flag|=FLAG_CONNECTED;
    tx_buff_head=0;
    tx_buff_tail=0;  
    tx_buff_count=0;
}
void User_App_Check_Timers(void)
{
    u_int32 current_clk = HW_Get_Native_Clk_Avoid_Race();
    extern t_LE_Config LE_config;
    t_LE_Connection* p_connection  = LEconnection_Find_Link_Entry(LE_config.active_link);
    if  ((LEapp_Config.SMP_security_request_timer!=  BT_TIMER_OFF) &&
            (((LEapp_Config.SMP_security_request_timer - current_clk - 1) & BT_CLOCK_MAX_TICKS) >= BT_CLOCK_MAX_TIMEOUT))
    {
        if(LEconnection_LE_Connected())
        {
            LE_APP_Connected();
            LEapp_Config.SMP_security_request_timer = BT_TIMER_OFF;
#if(GATT_SERVICE_USER_DEFINE)
            LEsmp_Initiate_Security(0xFFFF, SMP_AUTHREQ_BONDING_MITM);
#else
            if(!LEsmp_Initiate_Security(0xFFFF, SMP_AUTHREQ_BONDING_NO_MITM))
            {
                p_connection->SMP_Enc_Active=0;
            }
#endif
        }
    }
    if  ((LEapp_Config.empty_packet_flag==0 && LEapp_Config.empty_packet_cnt==50)||(LEapp_Config.TAPP_L2CAP_PARA_UPDATE_Timer !=  BT_TIMER_OFF) &&
            (((LEapp_Config.TAPP_L2CAP_PARA_UPDATE_Timer - current_clk - 1) & BT_CLOCK_MAX_TICKS) >= BT_CLOCK_MAX_TIMEOUT))
    {
        if(LEconnection_LE_Connected())
        {
            LE_APP_Connected();
            LEapp_Config.empty_packet_cnt=0xffff;
            LEapp_Config.empty_packet_flag=1;
            LEapp_Config.TAPP_L2CAP_PARA_UPDATE_Timer = BT_TIMER_OFF;
            sys_flag|=FLAG_START_CONNECT_UPDATA;
#if(GATT_SERVICE_USER_DEFINE)

            LE_L2CAP_Connection_Update(0xFFFF,24,12,0,0x0258);
#else          
            if(sys_flag & FLAG_IOS_SERVICE)
            {
                LE_L2CAP_Connection_Update
                (
                    0xFFFF,//handle       :- ACL Handle for the link to the peer.
                    36,    //max_interval :- Maximum new connection interval acceptable 
                    24,    //min_interval :- Minimum new connection interval acceptable
                    4,     //latency      :- The requested latency
                    0x0258 //timeout      :- The supervision Timeout on the link.
                );
            }
            else
            {
                LE_L2CAP_Connection_Update
                (
                    0xFFFF,//handle       :- ACL Handle for the link to the peer.
                    24,    //max_interval :- Maximum new connection interval acceptable 
                    24,    //min_interval :- Minimum new connection interval acceptable
                    30,    //latency      :- The requested latency
                    0x0258 //timeout      :- The supervision Timeout on the link.
                );
            }


#endif
        }
    }
    
#if(KEY_POWER_ON_ENABLE)
    if  ((!LEconnection_LE_Connected())&&(LEapp_Config.TAPP_Advertising_Timer !=  BT_TIMER_OFF) &&
            (((LEapp_Config.TAPP_Advertising_Timer - current_clk - 1) & BT_CLOCK_MAX_TICKS) >= BT_CLOCK_MAX_TIMEOUT))
    {
        LEapp_Config.TAPP_Advertising_Timer = BT_TIMER_OFF;
        Enter_Deep_sleep();
    }
#endif
    if ((LEapp_Config.ancs_config_start_timer !=  BT_TIMER_OFF) &&
            (((LEapp_Config.ancs_config_start_timer - current_clk) & BT_CLOCK_MAX_TICKS) >= BT_CLOCK_MAX_TIMEOUT))
    {
        LEapp_Config.ancs_config_start_timer = BT_TIMER_OFF;
        Ancs_subsNotifSrc();
    }
}
/*******************************************************
 * GERERIC ACCESS PROFILE DEFINITION
 * Handle 0x10 to 0x1A
 *
 * Peripheral Privacy is at 0x18
 * ReConnection Addr  is at 0x1A
 ******************************************************/
u_int16 App_Setup_GAP_GATT_DB(void)
{
    u_int16 handle = 1; /* GAP handles goes from 0x10- 0x1B   */
    _GATTserver_Add_Service(PRIMARY_SERVICE_16BIT, handle,0x00,GENERIC_ACCESS_PROFILE);
    handle++;
    _GATTserver_Add_Characteristic_Declaration(handle,DEVICE_NAME,0x02);
    handle++;
    _GATTserver_Add_Characteristic_Value(handle,DEVICE_NAME,NO_LOCAL_NOTIFY,GATT_PERMISSION_READ |GATT_PERMISSION_WRITE,sizeof(gap_name_array)-1,gap_name_array);
    handle++;
    _GATTserver_Add_Characteristic_Declaration(handle,APPERANCE,0x02);
    handle++;
    _GATTserver_Add_Characteristic_Value(handle,APPERANCE,NO_LOCAL_NOTIFY,GATT_PERMISSION_READ|GATT_PERMISSION_WRITE,sizeof(gap_appearance_array),gap_appearance_array);
    handle++;
#if (PRH_BS_CFG_SYS_LE_GAP_PRIVACY_SUPPORTED==1)
    _GATTserver_Add_Characteristic_Declaration(handle,PERIPHERAL_PRIVACY_FLAGS,0x02);
    handle++;
    _GATTserver_Add_Characteristic_Value(handle,PERIPHERAL_PRIVACY_FLAGS,NO_LOCAL_NOTIFY,GATT_PERMISSION_READ|GATT_PERMISSION_WRITE,1,&GATTprivacy_Flags);
    handle++;
#endif
    _GATTserver_Add_Characteristic_Declaration(handle,PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS,0x02);
    handle++;
    _GATTserver_Add_Characteristic_Value(handle,PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS,NO_LOCAL_NOTIFY,GATT_PERMISSION_READ,8,gap_connection_params);
    handle++;
    g_handle = handle;
    return handle;
}
/*******************************************************
 * GATT PROFILE DEFINITION
 * Handle 0x20 to 0x22
 *
 * Service Changed is at 0x22
 *
 ******************************************************/
u_int16 App_Setup_GATT_GATT_DB(void)
{
    u_int16 handle = g_handle;
    _GATTserver_Add_Service(PRIMARY_SERVICE_16BIT, handle,0x00,GENERIC_ATTRIBUTE_PROFILE);
    handle++;
    _GATTserver_Add_Characteristic_Declaration(handle,SERVICE_CHANGED,0x20);
    handle++;
    _GATTserver_Add_Characteristic_Value(handle,SERVICE_CHANGED,NO_LOCAL_NOTIFY,0x00,4,Service_Change_Range);
    handle++;
    _GATTserver_Add_Char_Descriptor(handle,CLIENT_CHARACTERISTIC_CONFIGURATION,GATT_PERMISSION_READ|GATT_PERMISSION_WRITE,0x02,GATT_service_change_CCC);
    handle++;
    g_handle = handle;
    return handle;
}
/*******************************************************
 * DERVICE INFORMATION PROFILE DEFINITION
 * Handle 0x30 to 0x42
 *
 ******************************************************/
u_int16 App_Setup_DEV_INFO_GATT_DB(void)
{
    u_int16 handle = g_handle;
    _GATTserver_Add_Service(PRIMARY_SERVICE_16BIT, handle,0x00,DEVICE_INFORMATION);
    handle++;
    _GATTserver_Add_Characteristic_Declaration(handle,GATT_CHAR_MANUFACTURER_NAME,0x02);
    handle++;
    _GATTserver_Add_Characteristic_Value(handle,GATT_CHAR_MANUFACTURER_NAME,NO_LOCAL_NOTIFY,GATT_PERMISSION_READ,sizeof(manufacturer_name_string)-1,manufacturer_name_string);/* handle == 30 */
    handle++;
    _GATTserver_Add_Characteristic_Declaration(handle,GATT_CHAR_MODEL_NUMBER,0x02);
    handle++;
    _GATTserver_Add_Characteristic_Value(handle,GATT_CHAR_MODEL_NUMBER,NO_LOCAL_NOTIFY,GATT_PERMISSION_READ,6,model_number_string);
    handle++;
    _GATTserver_Add_Characteristic_Declaration(handle,GATT_CHAR_SERIAL_NUMBER,0x02);
    handle++;
    _GATTserver_Add_Characteristic_Value(handle,GATT_CHAR_SERIAL_NUMBER,NO_LOCAL_NOTIFY,GATT_PERMISSION_READ,10,serial_number_string);
    handle++;
    _GATTserver_Add_Characteristic_Declaration(handle,GATT_CHAR_FW_REVISION,0x02);
    handle++;
    _GATTserver_Add_Characteristic_Value(handle,GATT_CHAR_FW_REVISION,NO_LOCAL_NOTIFY,GATT_PERMISSION_READ,4,fw_revision_string);
    handle++;
    _GATTserver_Add_Characteristic_Declaration(handle,GATT_CHAR_HW_REVISION,0x02);
    handle++;
    _GATTserver_Add_Characteristic_Value(handle,GATT_CHAR_HW_REVISION,NO_LOCAL_NOTIFY,GATT_PERMISSION_READ,4,hw_revision_string);
    handle++;
    _GATTserver_Add_Characteristic_Declaration(handle,GATT_CHAR_SW_REVISION,0x02);
    handle++;
    _GATTserver_Add_Characteristic_Value(handle,GATT_CHAR_SW_REVISION,NO_LOCAL_NOTIFY,GATT_PERMISSION_READ,4,sw_revision_string);
    handle++;
    _GATTserver_Add_Characteristic_Declaration(handle,GATT_CHAR_SYSTEM_ID,0x02);
    handle++;
    _GATTserver_Add_Characteristic_Value(handle,GATT_CHAR_SYSTEM_ID,NO_LOCAL_NOTIFY,GATT_PERMISSION_READ,8,system_id);
    handle++;
    _GATTserver_Add_Characteristic_Declaration(handle,GATT_CHAR_REG_CERT,0x02);
    handle++;
    _GATTserver_Add_Characteristic_Value(handle,GATT_CHAR_REG_CERT,NO_LOCAL_NOTIFY,GATT_PERMISSION_READ,sizeof(IEEE_Reg_Cert),IEEE_Reg_Cert);
    handle++;
    _GATTserver_Add_Characteristic_Declaration(handle,GATT_CHAR_PnP_ID,0x02);/* handle == 33 */
    handle++;
    _GATTserver_Add_Characteristic_Value(handle,GATT_CHAR_PnP_ID,NO_LOCAL_NOTIFY,GATT_PERMISSION_READ/*|GATT_PERMISSION_AUTHENTICATED*/,7,pnp_id);/* handle == 34 */
    handle++;
    g_handle=handle;
    return handle;
}
u_int8 battery_level = 5;
u_int16 battery_level_handle;
u_int8 Battery_Service_CCO[2] = {0x01,0x00};
u_int8 battery_service_format[7] = "battery";

u_int16 App_Setup_BATTERY_SERVICE_GATT_DB(void)
{
    u_int16 handle = g_handle;
    _GATTserver_Add_Service(PRIMARY_SERVICE_16BIT, handle,0x00,BATTERY_SERVICE);
    handle++;
    _GATTserver_Add_Characteristic_Declaration(handle,BATTERY_LEVEL ,0x12);//Characteristic Properties// bit 0 :Broadcast, bit 1 : Read , bit 2 : Write Without Response, bit 3 : Write
    // bit 4 : Notify, bit 5 : Indicate, bit 6 : Authenticated Signed Writes,
    //bit 7 : Extended Properties
    handle++;
    _GATTserver_Add_Characteristic_Value(handle,BATTERY_LEVEL,NO_LOCAL_NOTIFY,GATT_PERMISSION_READ,1,&battery_level);//battery level initial value for var declare
    battery_level_handle = handle;
	handle++;
    _GATTserver_Add_Char_Descriptor(handle,CLIENT_CHARACTERISTIC_CONFIGURATION,GATT_PERMISSION_READ|GATT_PERMISSION_WRITE,0x02,Battery_Service_CCO);

    handle++;
    _GATTserver_Add_Char_Descriptor(handle,CHARACTERISTIC_PRESENTATION_FORMAT,GATT_PERMISSION_READ | GATT_PERMISSION_WRITE,0x07,battery_service_format);
    handle++;
    g_handle=handle;
    return handle;
}
